#include"JsObject.h"
#include"JsContext.h"
#include"JsEngine.h"
#include"JsVm.h"
#include"JsValue.h"
#include"JsList.h"
#include"JsSys.h"
#include"JsDebug.h"
#include"JsError.h"
#include"JsFunction.h"
#include"JsAst.h"
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
/*
	标准Object类型的内置属性,
	放置在Value中
*/
struct JsStandardSelf{
	/*临界数据*/
	JsList 					propertys;
	/*临界资源 迭代器记录区*/
	JsList					iterators;
	/*属性(propertys, iterators)锁*/
	JsLock 					lock;
};

struct JsProperty{
	char* name;
	struct JsValue* value;
	int attr;
};
//当一个对象迭代完毕后, 重置属性, 并且挂载到下一个对象的iterators上
//如果该对象的属性在迭代过程中有被删除的, 则该迭代器失效useable = FALSE;
//如果再使用该迭代器, 则throw = error
struct JsIterator{
	int useable ;//是否可以使用
	int pos; //当前迭代到第几个属性
	int size;//创建迭代器时候, 对象的属性大小
	int slot;//在Object.iterators的第几个槽中
	struct JsObject* obj;//正在迭代的对象
};
//----------------------------------------------------------------------------------
/*标准对象内置的函数*/
static void JsStandardGet( struct JsObject *obj,  char *prop,int* flag, struct JsValue *res);
static void JsStandardPut( struct JsObject *obj, char *prop, struct JsValue *val, int flags);
static void JsStandardCanPut( struct JsObject *obj, char *prop,struct JsValue* res);
static void JsStandardHasProperty( struct JsObject *obj, char *prop,struct JsValue* res);	
static void JsStandardDelete( struct JsObject *obj,  char *prop,struct JsValue* res);
static void JsStandardHasOwnProperty( struct JsObject *obj, char *prop,struct JsValue* res);
static void JsStandardDefaultValue( struct JsObject *obj, int hint, struct JsValue *res);
static void JsStandardCall(struct JsObject *obj, struct JsObject *thisobj,int argc, struct JsValue **argv, struct JsValue *res);
static void JsStandardConstruct(struct JsObject *obj, struct JsObject *thisobj,int argc, struct JsValue **argv, struct JsValue *res);
static void JsStandardHasInstance(struct JsObject *obj, struct JsValue *instance,struct JsValue* res);
static struct JsObject*  JsStandardNextValue(struct JsObject* obj, JsIter* piter,int initialized, struct JsValue* res);

//----------------
static struct JsObject* JsCreateBaseObject();
static void noticeDel(struct JsStandardSelf* self);
static struct JsObject* jsCreateActivationObject(struct JsObject* fun,int argc, struct JsValue** argv);
static struct JsValue* jsCreateArguments(struct JsObject* fun,int argc, struct JsValue** argv);
//----------------
struct JsObject* JsCreateStandardObject(){
	struct JsValue v;
	struct JsObject* obj;
	obj = JsCreateBaseObject();
	//配置Prototype属性
	JsFindValue(NULL,"Object",&v);
	if(v.type != JS_UNDEFINED){
		JsAssert(v.type == JS_OBJECT);
		(*v.u.object->Get)(v.u.object,"prototype",NULL,&v);
		JsAssert(v.type == JS_OBJECT);
		obj->Prototype =  v.u.object;
	}else{
		obj->Prototype = NULL;
	}
	return obj;
}
struct JsObject* JsCreateFunctionObject(JsList scope,int inst){
	struct JsValue v;
	struct JsObject* obj;
	obj	= JsCreateBaseObject();
	//配置Prototype
	JsFindValue(NULL,"Function",&v);
	if(v.type != JS_UNDEFINED){
		JsAssert(v.type == JS_OBJECT);
		(*v.u.object->Get)(v.u.object,"prototype",NULL,&v);
		JsAssert(v.type == JS_OBJECT);
		obj->Prototype =  v.u.object;
	}else{
		obj->Prototype = NULL;
	}
	//配置Class属性	
	obj->Class = "Function";	
	//配置函数特有标准属性
	if(inst)
		obj->HasInstance = &JsStandardHasInstance;
	//配置Scope
	JsListInit(&obj->Scope);
	if(scope)
		JsListCopy(obj->Scope,scope);
	else
		JsListPush(obj->Scope,JsGetVm()->Global);
	return obj;
}


struct JsObject* JsCreateStandardFunctionObject(JsList scope){
	struct JsValue v;
	struct JsObject* obj;
	obj	= JsCreateBaseObject();
	//配置Prototype
	JsFindValue(NULL,"Function",&v);
	if(v.type != JS_UNDEFINED){
		JsAssert(v.type == JS_OBJECT);
		(*v.u.object->Get)(v.u.object,"prototype",NULL,&v);
		JsAssert(v.type == JS_OBJECT);
		obj->Prototype =  v.u.object;
	}else{
		obj->Prototype = NULL;
	}
	//配置Class属性	
	obj->Class = "Function";	
	//配置函数特有标准属性
	obj->Construct = &JsStandardConstruct;
	obj->Call = &JsStandardCall;
	obj->HasInstance = &JsStandardHasInstance;
	//配置Scope
	JsListInit(&obj->Scope);
	if(scope)
		JsListCopy(obj->Scope,scope);
	else
		JsListPush(obj->Scope,JsGetVm()->Global);
	return obj;
}

void JsDarkGet(struct JsObject *obj, char *prop,int* flag, struct JsValue *res){
	JsThrowString("TypeError");
}
void JsDarkPut(struct JsObject *obj,char *prop, struct JsValue *value, int flags){
	return;
}
void JsDarkBoolean(struct JsObject *obj,char *prop,struct JsValue* res){
	JsThrowString("TypeError");
}
void JsDarkCall(struct JsObject *obj, struct JsObject *thisobj,
				int argc, struct JsValue **argv, struct JsValue *res){
	JsThrowString("TypeError");
				
}
void JsDarkHasInstance(struct JsObject *obj, struct JsValue *instance,struct JsValue* res){
	JsThrowString("TypeError");
	return;	
}
void JsDarkDefaultValueFn(struct JsObject *obj,int type, struct JsValue *res){
	JsThrowString("TypeError");
}
struct JsObject* JsDarkNextValueFn(struct JsObject* obj, JsIter* iter,int initialized,struct JsValue* res){
	JsThrowString("TypeError");
	return NULL;
}



//----------------------------------------------------------------------
static struct JsObject* JsStandardNextValue( struct JsObject* obj, JsIter* piter,int initialized, struct JsValue* res){
	
	struct JsStandardSelf* self;
	struct JsIterator* iter;
	struct JsProperty* p;
	
	//初始化阶段
	if(initialized == FALSE){
		self = (struct JsStandardSelf*) obj->self;
		JsLockup(self->lock);
		iter = (struct JsIterator*) JsMalloc(sizeof(struct JsIterator));
		iter->useable = TRUE;
		iter->pos = -1;
		iter->size = JsListSize(self->propertys);
		iter->obj = obj;
		JsListPush(self->iterators,iter);
		//添加该迭代器在obj中的位置
		iter->slot = JsListSize(self->iterators);
		//赋值
		*piter = iter;
		JsUnlock(self->lock);
	}
	
	//迭代阶段
	JsAssert(piter != NULL && *piter != NULL);
	
	iter = *piter;
	//默认为JS_UNDEINFED;
	res->type = JS_UNDEFINED;

	if(iter->useable == FALSE){
		JsThrowString("Iterator Throw Error");
		return NULL;
	}
	//迭代已经完成
	if(iter->obj == NULL)
		return NULL;
		
	self = (struct JsStandardSelf*)iter->obj->self;
	JsLockup(self->lock);
	for(;iter->pos < iter->size -1;){
		iter->pos ++;
		p = (struct JsProperty*) JsListGet(self->propertys,iter->pos);
		if(p->attr & JS_OBJECT_ATTR_DONTENUM)
			continue;
		res->type = JS_STRING;
		res->u.string = p->name;
		//解锁
		JsUnlock(self->lock);
		return obj;
	}
	//该对象已经循环完毕
	//从对象上删除它
	JsListRemove(self->iterators,iter->slot);
	//暂时标记为不可用
	iter->useable = FALSE;
	//修改对象
	iter->obj = iter->obj->Prototype;
	iter->pos = -1;
	JsUnlock(self->lock);

	if(iter->obj == NULL)
		return NULL;
	return (*iter->obj->NextValue)(iter->obj,piter, FALSE,res);
}

/* Standard Object对象方法, 可以给Standard类型的对象填充的内部属性, 不包含函数填充*/
static void JsStandardGet(struct JsObject *obj, char *prop,int* flag, struct JsValue *res){
	int i,size;
	struct JsProperty* p;
	struct JsStandardSelf* self;
	self = (struct JsStandardSelf*)obj->self;
	//锁住
	JsLockup(self->lock);
	size = JsListSize(self->propertys);
	for(i=0;i<size;++i){
		p = (struct JsProperty*)JsListGet(self->propertys,i);
		if(strcmp(p->name,prop) == 0){
			*res = *p->value;
			if(flag != NULL)
				*flag = p->attr;
			JsUnlock(self->lock);
			return;
		}
	}
	//没有发现
	JsUnlock(self->lock);
	if(!obj->Prototype)
		res->type = JS_UNDEFINED;
	else
		(*obj->Prototype->Get)(obj->Prototype,prop,flag,res);

}
				
void JsStandardPut(struct JsObject *obj, char *prop, struct JsValue *val, int flags){
	int i,size;
	struct JsProperty* p;
	struct JsStandardSelf* self;
	struct JsValue v;
	self = (struct JsStandardSelf*)obj->self;
	JsAssert(val != NULL);
	JsLockup(self->lock);
	(*obj->CanPut)(obj,prop,&v);
	if(v.type == JS_BOOLEAN && v.u.boolean  == FALSE){
		JsUnlock(self->lock);
		return;
	}
	
	size = JsListSize(self->propertys);
	for(i=0;i<size;++i){
		p = (struct JsProperty*)JsListGet(self->propertys,i);
		if(strcmp(p->name,prop) == 0){
			//发现同名属性, 则覆盖value. attr 不修改
			p->value = val;
			JsUnlock(self->lock);
			return;
		}
	}
	//没有发现该属性, 则新添加一个新的属性
	p = (struct JsProperty*)JsMalloc(sizeof(struct JsProperty));
	p->name = prop;
	p->value = val;
	p->attr = flags;
	JsListPush(self->propertys,p);
	JsUnlock(self->lock);
	return;
}
				
static void  JsStandardCanPut(struct JsObject *obj, char *prop,struct JsValue* res){
	int i,size;
	struct JsProperty* p;
	struct JsStandardSelf* self;
	res->type = JS_BOOLEAN;
	self = (struct JsStandardSelf*)obj->self;
	JsLockup(self->lock);
	size = JsListSize(self->propertys);
	for(i=0;i<size;++i){
		p = (struct JsProperty*)JsListGet(self->propertys,i);
		if(strcmp(p->name,prop) == 0){
			JsUnlock(self->lock);
			if(p->attr & JS_OBJECT_ATTR_READONLY)
				res->u.boolean  = FALSE;
			else
				res->u.boolean  = TRUE;
			return;
		}
	}
	JsUnlock(self->lock);
	if(!obj->Prototype){
		res->u.boolean  = TRUE;
		return;
	}
	return ((*obj->Prototype->CanPut)(obj->Prototype,prop,res));
}
static void JsStandardHasOwnProperty(struct JsObject *obj, char *prop,struct JsValue* res){
	int i,size;
	struct JsProperty* p;
	struct JsStandardSelf* self;
	res->type =JS_BOOLEAN;
	self = (struct JsStandardSelf*)obj->self;
	JsLockup(self->lock);
	size = JsListSize(self->propertys);
	for(i=0;i<size;++i){
		p = (struct JsProperty*)JsListGet(self->propertys,i);
		if(strcmp(p->name,prop) == 0){
			JsUnlock(self->lock);
			res->u.boolean = TRUE;
			return;
		}
	}
	JsUnlock(self->lock);
	//没有发现
	res->u.boolean = FALSE;
	return;
				
}				
static void JsStandardHasProperty(struct JsObject *obj, char *prop,struct JsValue* res){
	int i,size;
	struct JsProperty* p;
	struct JsStandardSelf* self;
	res->type = JS_BOOLEAN;
	self = (struct JsStandardSelf*)obj->self;
	JsLockup(self->lock);
	size = JsListSize(self->propertys);
	for(i=0;i<size;++i){
		p = (struct JsProperty*)JsListGet(self->propertys,i);
		if(strcmp(p->name,prop) == 0){
			JsUnlock(self->lock);
			res->u.boolean = TRUE;
			return;
		}
	}
	JsUnlock(self->lock);
	if(!obj->Prototype){
		res->u.boolean = FALSE;
		return;
	}
	return ((*obj->Prototype->HasProperty)(obj->Prototype,prop,res));
}
						
static void JsStandardDelete(struct JsObject *obj, char *prop,struct JsValue* res){
	int i,size;
	struct JsProperty* p;
	struct JsStandardSelf* self;
	res->type = JS_BOOLEAN;
	self = (struct JsStandardSelf*)obj->self;
	JsLockup(self->lock);
	size = JsListSize(self->propertys);
	for(i=0;i<size;++i){
		p = (struct JsProperty*)JsListGet(self->propertys,i);
		if(strcmp(p->name,prop) == 0){
			if(p->attr & JS_OBJECT_ATTR_DONTDELETE){
				JsUnlock(self->lock);
				res->u.boolean = FALSE;
				return;
			}
			//删除该属性
			JsListRemove(self->propertys,i);
			//对Iterator做处理
			noticeDel(self);
			//解锁
			JsUnlock(self->lock);
			res->u.boolean = TRUE;
			return;
		}
	}
	JsUnlock(self->lock);	
	res->u.boolean = TRUE;
	return;
}
				
static void JsStandardDefaultValue(struct JsObject *obj, int hint, struct JsValue *res){
	struct JsValue res0;
//r1:
	if(hint != JS_OBJECT_HIT_TYPE_NUMBER)
		(*obj->Get)(obj,"toString",NULL,&res0);
	else
		(*obj->Get)(obj,"valueOf",NULL,&res0);
//r2:
	if(res0.type != JS_OBJECT || res0.u.object->Call == NULL)
		goto r5;
//r3:
	(*res0.u.object->Call)(res0.u.object,obj,0,NULL,res);
//r4:
	if(res->type != JS_OBJECT && res->type != JS_REFERENCE 
			&& res->type != JS_COMPLETION){
		return ;
	}
r5: 	
	if(hint != JS_OBJECT_HIT_TYPE_NUMBER)
		(*obj->Get)(obj,"valueOf",NULL,&res0);
	else
		(*obj->Get)(obj,"toString",NULL,&res0);
//r6:
	if(res0.type != JS_OBJECT || res0.u.object->Call == NULL)
		goto r9;
//r7:
	(*res0.u.object->Call)(res0.u.object,obj,0,NULL,res);
//r8
	//Primitive类型数据才被接受
	if(res->type != JS_OBJECT && res->type != JS_REFERENCE 
			&& res->type != JS_COMPLETION){
		return ;
	}
r9:
	JsThrowString("TypeError");
	return;
	
}
/* 和standard 函数连用*/
static void JsStandardCall(struct JsObject *obj,struct JsObject *thisobj,
			int argc, struct JsValue **argv, struct JsValue *res){
	struct JsFunction* f;
	struct JsObject* ac;
	JsList newScope;
	JsList saveScope;
	struct JsObject* saveThisObj;
	int saveVarattr;
	//从线程中获得JsEngine
	struct JsEngine* e = JsGetTlsEngine();
	
	f = (struct JsFunction*)obj->Value;
	if(f->fn == NULL){
		res->type = JS_UNDEFINED;
		return;
	}
	if(f->sync)
		JsLockup(f->syncLock);
	//ActivationObject对象处理
	ac = jsCreateActivationObject(obj,argc,argv);
	//创建一个新的Scope List
	JsListInit(&newScope);
	JsListCopy(newScope,obj->Scope);
	JsListPush(newScope,ac);
	
	//处理上下文
	saveScope = e->exec->scope;
	e->exec->scope = newScope;
	saveThisObj = e->exec->thisObj;
	e->exec->thisObj = (thisobj != NULL ? thisobj : e->jsVm->Global);
	saveVarattr = e->exec->varattr;
	e->exec->varattr = JS_OBJECT_ATTR_DONTDELETE;
	struct JsStack* stack = (struct JsStack*)JsMalloc(sizeof(struct JsStack));
	stack->loc = NULL;
	stack->function = f;
	if(f->type == JS_FUNCTION_EVAL){
		struct JsAstNode* node = (struct JsAstNode*)f->data;
		stack->loc = node->location;
	}
	JsListPush(e->exec->stack,stack);
	
	//执行函数
	res->type =JS_UNDEFINED;
	(*f->fn)(e,f->data,res);
	
	//还原环境
	e->exec->scope = saveScope;
	e->exec->thisObj = saveThisObj;
	e->exec->varattr = saveVarattr;
	JsListRemove(e->exec->stack,JS_LIST_END);
	
	//结果处理
	if(res->type == JS_COMPLETION){

		if(res->u.completion.type == JS_COMPLETION_RETURN){
			*res = *res->u.completion.value;
		}else if(res->u.completion.type == JS_COMPLETION_THROW){
			//不处理
		}else{
			//JS_COMPLETION_NORMAL, JS_COMPLETION_BREAK, JS_COMPLETION_CONTINUE
			res->type = JS_UNDEFINED;
		}
	}else if(res->type == JS_REFERENCE){
		res->type = JS_UNDEFINED;
	}//res->type = JS_OBJECT, JS_NULL, JS_BOOLEAN ...
	
	if(f->sync)
		JsUnlock(f->syncLock);
	return;
}
			
static void JsStandardConstruct(struct JsObject *obj, struct JsObject *thisobj,
			int argc, struct JsValue **argv, struct JsValue *res){
			
	struct JsObject* this0 = JsCreateStandardObject();
	struct JsValue res0;
	//获得构造函数的prototype属性
	(*obj->Get)(obj,"prototype",NULL,&res0);
	if(res0.type == JS_OBJECT)
		this0->Prototype = res0.u.object;
	//Call
	(*obj->Call)(obj,this0,argc,argv,res);
	if(res->type != JS_OBJECT){
		res->type = JS_OBJECT;
		res->u.object = this0;
	}
}
static void JsStandardHasInstance(struct JsObject *obj, struct JsValue *instance,
			struct JsValue* res){
	struct JsValue res0;
	struct JsObject* prototype;
	if(instance->type != JS_OBJECT){
		res->type = JS_BOOLEAN;
		res->u.boolean = FALSE;
		return;
	}
	(*obj->Get)(obj,"prototype",NULL,&res0);
	if(res0.type != JS_OBJECT){
		JsThrowString("TypeError");
		return;
	}
	prototype = instance->u.object->Prototype;
	//循环查询
	while(prototype != NULL){
		if(prototype == res0.u.object){
			res->type = JS_BOOLEAN;
			res->u.boolean = TRUE;
		}
		//下一个对象的原形
		prototype = prototype->Prototype;
	}
	//没有查询到
	res->type = JS_BOOLEAN;
	res->u.boolean = FALSE;
}


//-----------------------------------------------------------------------------
//self已经被上锁
static void noticeDel(struct JsStandardSelf* self){
	
	int size, i;
	struct JsIterator* iter ;
	size = JsListSize(self->iterators);
	for(i=0;i< size; ++i){
		iter = (struct JsIterator*) JsListGet(self->iterators,JS_LIST_FIRST);
		iter->useable = FALSE;
		JsListRemove(self->iterators,JS_LIST_FIRST);
	}
}
static struct JsObject* jsCreateActivationObject(struct JsObject* fun, int argc, 
					struct JsValue** argv){
	int i;
	struct JsFunction* f = (struct JsFunction*)fun->Value;
	//构建Activation
	struct JsObject* activationObj = JsCreateStandardObject();
	//不使用默认"Object"
	activationObj->Class = "Activation";
	//配置arguments对象
	(*activationObj->Put)(activationObj,"arguments",jsCreateArguments(fun,argc,argv),JS_OBJECT_ATTR_DONTDELETE);
	//构建Function Params
	for(i=0;i<f->argc && i< argc;++i){
		(*activationObj->Put)(activationObj,f->argv[i],argv[i],JS_OBJECT_ATTR_DONTDELETE);
	}
	//处理未被赋值的Params
	for(;i<f->argc;++i){
		struct JsValue* undef = (struct JsValue*)JsMalloc(sizeof(struct JsValue));
		(*activationObj->Put)(activationObj,f->argv[i],undef,JS_OBJECT_ATTR_DONTDELETE);
	}
	return activationObj;
}
static struct JsValue* jsCreateArguments(struct JsObject* fun,int argc, struct JsValue** argv){
	int i,size;
	struct JsObject* argumentsObj = JsCreateStandardObject();
	struct JsValue* length = (struct JsValue*)JsMalloc(sizeof(struct JsValue));
	length->type = JS_NUMBER;
	length->u.number = argc;
	//length
	(*argumentsObj->Put)(argumentsObj,"length",length,JS_OBJECT_ATTR_DONTENUM);
	struct JsValue* callee = (struct JsValue*)JsMalloc(sizeof(struct JsValue));
	callee->type = JS_OBJECT;
	callee->u.object = fun;
	(*argumentsObj->Put)(argumentsObj,"callee",callee,JS_OBJECT_ATTR_DONTENUM);
	
	//构建arguments[0]...[i]
	for(i =0 ; i < argc;++i){
		//计算整数的位数
		int number = i;
		while(number){
			number /=10;
			size++;
		}
		size += 2;
		char* buf = (char*)JsMalloc(size);
		sprintf(buf,"%d",i);
		(*argumentsObj->Put)(argumentsObj,buf,argv[i],JS_OBJECT_ATTR_DONTENUM);
	}
	//构建JsValue
	struct JsValue* arguments = (struct JsValue*)JsMalloc(sizeof(struct JsValue));
	arguments->type = JS_OBJECT;
	arguments->u.object  = argumentsObj;
	return arguments;
}

static struct JsObject* JsCreateBaseObject(){

	struct JsObject* obj;
	struct JsStandardSelf* self;
	obj = (struct JsObject*) JsMalloc(sizeof(struct JsObject));
	//Prototype
	obj->Prototype = NULL;
	//Class
	obj->Class = "Object";
	//都为标准函数
	obj->Get = &JsStandardGet;
	obj->Put = &JsStandardPut;
	obj->CanPut = &JsStandardCanPut;
	obj->HasProperty = &JsStandardHasProperty;
	obj->Delete = &JsStandardDelete;
	obj->DefaultValue = &JsStandardDefaultValue;
	
	obj->HasOwnProperty = &JsStandardHasOwnProperty;
	obj->NextValue = &JsStandardNextValue;
	
	//配置函数特有属性
	obj->Construct = &JsDarkCall;
	obj->Call = &JsDarkCall;
	obj->HasInstance = &JsDarkHasInstance;
	//Scope
	obj->Scope = NULL;
	//Value
	obj->Value = NULL;
	JsCreateLock(&obj->syncLock);
	
	//self
	self = (struct JsStandardSelf* )JsMalloc(sizeof(struct JsStandardSelf));	
	JsListInit(&self->propertys);	
	JsListInit(&self->iterators);
	JsCreateLock(&self->lock);
	obj->self = self;
	
	return obj;

}